package ca.seia.comp6521.a2.itemsetalgorithms;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import ca.seia.comp6521.a2.io.ObjectSerializer;
import ca.seia.comp6521.a2.itemsetstorage.CharTriplet;
import ca.seia.comp6521.a2.itemsetstorage.IntItems;
import ca.seia.comp6521.a2.itemsetstorage.IntPair;
import ca.seia.comp6521.a2.itemsetstorage.IntTriplet;

public class CandidateGenerator {
	
	public static int MAX_CHAR_TRIPLES_IN_MEMORY = 135000;//266464 real max for file candidate of size three
	public static int MAX_INTPAIRS_IN_MEMORY = 19363;
	public static int SAFE_TRIPLET_AMOUNT_FOR_SERIALIZING = 130000;
	public static int MAX_CHAR_TRIPLET_DEFAULT_ARRAY_LIST_COUNT = 80000;
	public static int MAX_INT_TRIPLET_DEFAULT_ARRAY_LIST_COUNT = 60000;
	public static ObjectSerializer objectSerializer;
	
	public static List<IntItems>  generateCandidateTriplets(List<IntPair> frequentPairs) {
		
		List<IntItems> triplets = new ArrayList<IntItems>(MAX_INT_TRIPLET_DEFAULT_ARRAY_LIST_COUNT);
		
		int keyLength = frequentPairs.size();
		for(int keyIndex = 0 ; keyIndex < keyLength ; keyIndex++) {
			for(int secondPairIndex = keyIndex + 1; secondPairIndex < keyLength ; secondPairIndex++) {
//				System.out.println("size of triplets " + triplets.size());
				IntItems triplet = IntItems.generateCandidateTriplet(frequentPairs.get(keyIndex), frequentPairs.get(secondPairIndex));
				if(triplet == null) {
					break;
				} else {
					triplets.add(triplet);
				}
			}
		}
		return triplets;
	}
	
	public static List<IntTriplet> generateCandidateIntTriplets(List<IntPair> frequentPairs) {
		
		List<IntTriplet> triplets = new ArrayList<IntTriplet>(MAX_INT_TRIPLET_DEFAULT_ARRAY_LIST_COUNT);
//		System.out.println(frequentPairs);
		int keyLength = frequentPairs.size();
		for(int keyIndex = 0 ; keyIndex < keyLength ; keyIndex++) {
			for(int secondPairIndex = keyIndex + 1; secondPairIndex < keyLength ; secondPairIndex++) {
//				System.out.println("size of triplets " + triplets.size());
				try {
				IntTriplet triplet = CandidateGenerator.generateCandidateIntTriplet(frequentPairs.get(keyIndex), frequentPairs.get(secondPairIndex));
				if(triplet == null) {
					break;
				} else {
					triplets.add(triplet);
				}
				} catch (OutOfMemoryError e) {
					System.gc();
					System.out.println(triplets.size());
					e.printStackTrace();
				}
			}
		}
		return triplets;
	}
	
	public static List<CharTriplet> generateCandidateCharTriplets(List<IntPair> frequentPairs) {
		
		List<CharTriplet> triplets = new ArrayList<CharTriplet>(MAX_CHAR_TRIPLET_DEFAULT_ARRAY_LIST_COUNT);
		
		
		int keyLength = frequentPairs.size();
		for(int keyIndex = 0 ; keyIndex < keyLength ; keyIndex++) {
			for(int secondPairIndex = keyIndex + 1; secondPairIndex < keyLength ; secondPairIndex++) {
//				System.out.println("size of triplets " + triplets.size());
				CharTriplet triplet = CandidateGenerator.generateCandidateCharTriplet(frequentPairs.get(keyIndex), frequentPairs.get(secondPairIndex));
				if(triplet == null) {
					break;
				} else {
					triplets.add(triplet);
				}
			}
		}
		return triplets;
	}
	
	public static List<CharTriplet> generateCandidateCharTripletsStoreToDisk(List<IntPair> frequentPairs) throws IOException {
		return generateCandidateCharTripletsStoreToDisk(frequentPairs,objectSerializer);
	}
	
	public static List<CharTriplet> readCandidateCharTripletFromDisk(int fileNumber) throws Exception {
		return objectSerializer.deserializeFromDisk(fileNumber);
	}
	
	public static int getNumberOfFilesToRead() {
		return objectSerializer.countNbrTimesSerializedToDisk;
	}
	
	public static List<CharTriplet> generateCandidateCharTripletsStoreToDisk(List<IntPair> frequentPairs, ObjectSerializer objectSerializer) throws IOException {
		
		List<CharTriplet> triplets = new ArrayList<CharTriplet>(MAX_CHAR_TRIPLET_DEFAULT_ARRAY_LIST_COUNT);
		int maxSizeBeforeSerialization = getMaxAmountForTripletStorage(frequentPairs.size());
		System.out.println("maxSizeBeforeSerialization " + maxSizeBeforeSerialization);
		
		int keyLength = frequentPairs.size();
		for(int keyIndex = 0 ; keyIndex < keyLength ; keyIndex++) {
			for(int secondPairIndex = keyIndex + 1; secondPairIndex < keyLength ; secondPairIndex++) {
//				System.out.println("size of triplets " + triplets.size());
				CharTriplet triplet = CandidateGenerator.generateCandidateCharTriplet(frequentPairs.get(keyIndex), frequentPairs.get(secondPairIndex));
				if(triplet == null) {
					break;
				} else {
					triplets.add(triplet);
					if(triplets.size() == maxSizeBeforeSerialization) {
//						System.out.println("serializing objects");
						//serialize to disk and read 
						objectSerializer.serializeToDisk(triplets);
						triplets.clear();
						triplets = null;
						triplets =  new ArrayList<CharTriplet>(MAX_CHAR_TRIPLET_DEFAULT_ARRAY_LIST_COUNT);
					}
				}
			}
		}
		return triplets;
	}
	
	public static int getMaxAmountForTripletStorage(int frequentPairSize) {
		if( frequentPairSize >= MAX_INTPAIRS_IN_MEMORY) {
			return SAFE_TRIPLET_AMOUNT_FOR_SERIALIZING;
		}else {
			return MAX_CHAR_TRIPLES_IN_MEMORY;
		}
	}
	
	public static CharTriplet generateCandidateCharTriplet(IntPair pair1, IntPair pair2 ) {
		CharTriplet triplet = null;
		if( pair1.getValOne() == pair2.getValOne())  {
			if(pair1.getValTwo() <= pair2.getValTwo()) {
				triplet = new CharTriplet(pair1.getValOne(),pair1.getValTwo(),pair2.getValTwo());
			} else {
				triplet = new CharTriplet(pair1.getValOne(),pair2.getValTwo(),pair1.getValTwo());
			}
		}
		return triplet;
	}
	
	public static IntTriplet generateCandidateIntTriplet(IntPair pair1, IntPair pair2 ) {
		IntTriplet triplet = null;
		if( pair1.getValOne() == pair2.getValOne())  {
			if(pair1.getValTwo() <= pair2.getValTwo()) {
				triplet = new IntTriplet(pair1.getValOne(),pair1.getValTwo(),pair2.getValTwo());
			} else {
				triplet = new IntTriplet(pair1.getValOne(),pair2.getValTwo(),pair1.getValTwo());
			}
		}
		return triplet;
	}
	
	public static IntItems generateCandidateTriplet(IntPair pair1, IntPair pair2 ) {
		IntItems triplet = null;
		if( pair1.getValOne() == pair2.getValOne())  {
			if(pair1.getValTwo() <= pair2.getValTwo()) {
				triplet = new IntItems(pair1.getValOne(),pair1.getValTwo(),pair2.getValTwo());
			} else {
				triplet = new IntItems(pair1.getValOne(),pair2.getValTwo(),pair1.getValTwo());
			}
		}
		return triplet;
	}
	
	public static IntItems generateCandidateItems(IntItems items1,IntItems items2, int numberOfItems) {
		int lengthItem1 = items1.getSize() - 1;
		int[] newItems = new int[numberOfItems];
		
		boolean subItemsAllEqual = true;
		for(int item1 = 0 ; item1 < lengthItem1 ; item1++) {
			if(items1.getItem(item1) != items2.getItem(item1)) {
				subItemsAllEqual = false;
				return null;
			}
			newItems[item1] = items1.getItem(item1);
		}
		if (items1.getItem(lengthItem1) <= items2.getItem(lengthItem1)) {
			newItems[lengthItem1] = items1.getItem(lengthItem1);
			newItems[lengthItem1+1] = items2.getItem(lengthItem1);
		}else {
			newItems[lengthItem1] = items2.getItem(lengthItem1);
			newItems[lengthItem1+1] = items1.getItem(lengthItem1);
		}
		return new IntItems(newItems);
	}
	
	
}
